﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Media.Imaging;

namespace RealTimeCharts.LineChart
{
    /// <summary>
    /// 绘图缓冲区
    /// </summary>
    public class AxisDataWindow : AxisWindow
    {
        // 缓冲区
        public Rect realRect;  // 以（0，0）为原点的区域
        private BitmapBuffer bitmapBuffer;
        private Color background;
        private Graphics gs;
        private byte[] mergePixels;

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="bgColor">背景颜色</param>
        /// <param name="originWidth">初始宽度</param>
        /// <param name="originHeight">初始高度</param>
        public AxisDataWindow(Color bgColor, int originWidth, int originHeight)
        {
            this.background = bgColor;
            //this.background = Color.FromArgb(0x00, 0xff, 0xff, 0xff); //全透明，只有数据线是不透明


            //初始化缓冲区
            realRect = new Rect(0, 0, originWidth, originHeight);
            bitmapBuffer = new BitmapBuffer((int)realRect.Width, (int)realRect.Height);
            gs = bitmapBuffer.CreateGraphics();

            bitmapBuffer.GetSource();

            WriteableBitmap myBitmap = bitmapBuffer.GetSource();
            mergePixels = new byte[(int)realRect.Height * (int)realRect.Width * myBitmap.Format.BitsPerPixel / 8];

            //gs.Clear(bgColor);
            gs.Clear(this.background);
        }

        public Graphics GetGraphics()
        {
            if (gs != null) return gs;
            if(bitmapBuffer != null)
            {
                gs = bitmapBuffer.CreateGraphics();
            }

            return gs;
        }

        public void Clear(Color color)
        {
            gs.Clear(color);
        }

        public void Resize(int width, int height)
        {
            this.realRect.Width = width;
            this.realRect.Height = height;

            bitmapBuffer = new BitmapBuffer((int)realRect.Width, (int)realRect.Height);
            gs = bitmapBuffer.CreateGraphics();

            gs.Clear(background);
        }

        public void ShowPolyLine(List<List<ValuePoint>> valuePoints,ColorLegend colorLegend)
        {
            gs.Clear(this.background);

            List<PolyLine> lines = new List<PolyLine>();
            for (int i = 0; i < valuePoints.Count; i++)
            {
                Pen pen;
                if (colorLegend != null && i < colorLegend.dataList.Count)
                {
                    pen = new Pen(colorLegend.dataList[i].color, 1);
                }
                else
                {
                    pen = new Pen(Color.Black, 1);
                }

                List<ValuePoint> values = valuePoints[i];

                int tmpEndIndex = 0;
                if (values.Count > 0)
                {
                    tmpEndIndex = values.Count - 1;

                    PolyLine line = MakePolyLine(gs, pen, values);
                    lines.Add(line);
                }

            }

            foreach (var l in lines)
            {
                l.Show();
            }
        }

        private PolyLine MakePolyLine(Graphics g,Pen pen,List<ValuePoint> points)
        {
            List<PixelPoint> pixelPoints = new List<PixelPoint>();

            foreach (var point in points)
            {
                PixelPoint pixelPoint = this.Point2Pixel(point);
                pixelPoints.Add(pixelPoint);
            }

            // Pen p = new Pen(Color.Black, 1);
            PolyLine line = new PolyLine(g, pixelPoints, pen);

            return line;
        }

        /// <summary>
        /// 放大/缩小操作
        /// </summary>
        /// <param name="zoomX">x轴放大倍数</param>
        /// <param name="zoomY">y轴放大倍数</param>
        public void Zoom(double zoomX, double zoomY)
        {
            //设置坐标系的Size
            this.windowRect.Width *= zoomX;
            this.windowRect.Height *= zoomY;
        }

        /// <summary>
        /// 图像移动
        /// </summary>
        /// <param name="offsetX"> >0: 右移，< 0左移</param>
        /// <param name="offsetY"> >0: 下移，< 0:上移</param>
        public void Move(int offsetX, int offsetY)
        {
            windowRect.X += offsetX;
            windowRect.Y += offsetY;
        }

        public WriteableBitmap Show()
        {
            bitmapBuffer.Flush();
            return bitmapBuffer.GetSource();
        }

        /// <summary>
        /// 自动调整坐标系，使显示区域位于缓冲区中心
        /// </summary>
        /// <param name="showWnd"></param>
        public void AutoFit(DataWnd showWnd)
        {
            ValuePoint valuePoint1 = new ValuePoint(showWnd.valueRangeX.minValue, showWnd.valueRangeY.maxValue);
            ValuePoint valuePoint2 = new ValuePoint(showWnd.valueRangeX.maxValue, showWnd.valueRangeY.minValue);
            PixelPoint pixelPoint1 = this.Point2Pixel(valuePoint1);
            PixelPoint pixelPoint2 = this.Point2Pixel(valuePoint2);

            Rect rect = new Rect(new System.Windows.Point(pixelPoint1.X, pixelPoint1.Y), new System.Windows.Point(pixelPoint2.X, pixelPoint2.Y));

            //调整坐标系
            AutoFit(rect);
        }

        /// <summary>
        /// 自动调整坐标系，使显示区域位于缓冲区中心
        /// </summary>
        /// <param name="rect"></param>
        public void AutoFit(Rect rect)
        {
            //调整真实坐标系，使rect位于其中心
            double offsetX = (realRect.Width - rect.Width) / 2 - rect.X;
            this.windowRect.X += offsetX;
            if (this.windowRect.X > 0) this.windowRect.X = 0;


            double offsetY = (realRect.Height - rect.Height) / 2 - rect.Y;
            this.windowRect.Y += offsetY;
            if (this.windowRect.Y > 0) this.windowRect.Y = 0;
        }

        public void Copy(Int32Rect rect, BitmapBuffer targetBuffer, PixelPoint startPoint)
        {
            WriteableBitmap source = bitmapBuffer.GetSource();
            WriteableBitmap target = targetBuffer.GetSource();

            target.Lock();

            source.CopyPixels(rect, target.BackBuffer + startPoint.Y * target.BackBufferStride + startPoint.X * target.Format.BitsPerPixel / 8, target.PixelHeight * target.BackBufferStride, target.BackBufferStride);
            target.AddDirtyRect(new Int32Rect(startPoint.X, startPoint.Y, rect.Width, rect.Height));
            target.Unlock();

            
        }
        public void Copy(BitmapBuffer targetBuffer, PixelPoint startPoint)
        {
            Graphics g = Graphics.FromImage(targetBuffer.GetBitmap());
            g.DrawImage(bitmapBuffer.GetBitmap(), new System.Drawing.Point(startPoint.X, startPoint.Y));
        }
        public void Copy(DataWnd wnd, BitmapBuffer targetBuffer,PixelPoint startPoint)
        {
            ValuePoint valuePoint1 = new ValuePoint(wnd.valueRangeX.minValue, wnd.valueRangeY.maxValue);
            ValuePoint valuePoint2 = new ValuePoint(wnd.valueRangeX.maxValue, wnd.valueRangeY.minValue);
            PixelPoint pixelPoint1 = this.Point2Pixel(valuePoint1);
            PixelPoint pixelPoint2 = this.Point2Pixel(valuePoint2);


            int width = pixelPoint2.X - pixelPoint1.X;
            int height = pixelPoint2.Y - pixelPoint1.Y;
            Int32Rect rect = new Int32Rect(pixelPoint1.X, pixelPoint1.Y, width, height);

            //Pen borderPen = new Pen(new SolidBrush(Color.Red), 3);
            //gs.DrawRectangle(borderPen, new Rectangle(rect.X, rect.Y, rect.Width, rect.Height));

            //Console.WriteLine("copy data window, width:{0}, height:{1}", width, height);

            Copy(rect, targetBuffer, startPoint);
        }

        /// <summary>
        /// 判断点是否在绘图范围内
        /// </summary>
        /// <param name="r"></param>
        /// <returns></returns>
        public bool voerflow(Rect r)
        {
            PixelPoint pixelPoint1 = new PixelPoint((int)r.TopLeft.X, (int)r.TopLeft.Y);
            PixelPoint pixelPoint2 = new PixelPoint((int)r.BottomRight.X, (int)r.BottomRight.Y);

            return overflow(pixelPoint1) && overflow(pixelPoint2);
        }
        /// <summary>
        /// 判断点是否在绘图范围内
        /// </summary>
        /// <param name="wnd"></param>
        /// <returns></returns>
        public bool overflow(DataWnd wnd)
        {
            ValuePoint value1 = new ValuePoint(wnd.valueRangeX.minValue, wnd.valueRangeY.maxValue);
            ValuePoint value2 = new ValuePoint(wnd.valueRangeX.maxValue, wnd.valueRangeY.minValue);

            PixelPoint pixelPoint1 = this.Point2Pixel(value1);
            PixelPoint pixelPoint2 = this.Point2Pixel(value2);

            return overflow(pixelPoint1) || overflow(pixelPoint2);
        }
        /// <summary>
        /// 判断点是否在绘图范围内
        /// </summary>
        /// <param name="p"></param>
        /// <returns></returns>
        private bool overflow(PixelPoint p)
        {
            if (p.X < realRect.Left || p.X > realRect.Right) return true;
            if (p.Y < realRect.Top || p.Y > realRect.Bottom) return true;

            return false;
        }
    }
}
